package com.katesoft.scale4j.persistent.spring;

import com.katesoft.scale4j.common.lock.IDistributedLockProvider;
import com.katesoft.scale4j.persistent.hibernate.StoreUpdateScriptsConfiguration;
import org.hibernate.cfg.Configuration;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.init.DatabasePopulator;

import javax.sql.DataSource;
import java.util.Map;
import java.util.Properties;

/**
 * @author kate2007
 */
public interface ILocalHibernateSessionBuilder extends DisposableBean, InitializingBean {
   /**
    * key to be used with distributed lock provider.
    * <p/>
    * for internal use actually, but may be used by client to retrieve status of update.
    */
   String RTTP_DB_UPDATE_LOCK = "rttp.schema.creation.lock";

   /**
    * remove inconsistency between hibernate meta-data and actual db.
    * <p/>
    * implementation class should simulate behaviour which is exactly the same as hibernate's
    * hbm.ddl=update.
    */
   void updateDatabaseSchema();

   /**
    * allows to inject pre-hibernate-schema-creation db populator.
    * <p/>
    * Clients may want to perform additional db population before hibernate will create/update
    * database(in case of db.update enabled)
    * <p/>
    * Implementation class should unsure this is done before actual schema update which is fired by
    * hibernate.
    * 
    * @param databasePopulator
    *           populator
    */
   void setDatabasePopulator(DatabasePopulator databasePopulator);

   /**
    * for clustered env clients probably would like to run schema update only from one server at the
    * same time, because parallel schema update can cause dead-locks or some other issue(even
    * performance issues).
    * <p/>
    * And actually they may want to run this operation only once - that why distributed lock
    * required to ensure this is done only once.
    * 
    * @param lockProvider
    *           distributed lock provider
    */
   void setLockProvider(IDistributedLockProvider lockProvider);

   /**
    * set client properties. also there is a small enrichment around hibernate envers and hibernate
    * search(setting default values).
    * 
    * @param hibernateProperties
    *           client properties.
    */
   void setHibernateProperties(Properties hibernateProperties);

   /**
    * Return the Configuration object used to build the SessionFactory.
    * <p/>
    * Allows access to configuration metadata stored there (rarely needed).
    * 
    * @return configuration instance
    */
   Configuration getConfiguration();

   /**
    * Set whether to execute a schema update after SessionFactory initialization.
    * <p/>
    * For details on how to make schema update scripts work, see the Hibernate documentation, as
    * this class leverages the same schema update script support in org.hibernate.cfg.Configuration
    * as Hibernate's own SchemaUpdate tool.
    * 
    * @param schemaUpdate
    *           value
    * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
    * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
    */
   void setSchemaUpdate(boolean schemaUpdate);

   /**
    * configuration with corresponds to hibernate schema create/drop/update schema
    * 
    * @param updateScriptsConfiguration
    *           client configuration
    */
   void setUpdateScriptsConfiguration(StoreUpdateScriptsConfiguration updateScriptsConfiguration);

   /**
    * configuration with corresponds to hibernate schema create/drop/update schema
    * 
    * @return update configuration
    */
   StoreUpdateScriptsConfiguration getUpdateScriptsConfiguration();

   /**
    * Specify the Hibernate event listeners to register, with listener types as keys and listener
    * objects as values.
    * <p/>
    * Instead of a single listener object, you can also pass in a list or set of listeners objects
    * as value.
    * <p>
    * See the Hibernate documentation for further details on listener types and associated listener
    * interfaces.
    * 
    * @param eventListeners
    *           Map with listener type Strings as keys and listener objects as values
    * @see org.hibernate.cfg.Configuration#setListener(String, Object)
    */
   void setEventListeners(final Map<String, Object> eventListeners);

   /**
    * Specify the JDBC DataSource that the JPA persistence provider is supposed to use for accessing
    * the database.
    * <p/>
    * This is an alternative to keeping the JDBC configuration in <code>persistence.xml</code>,
    * passing in a Spring-managed
    * 
    * @param datasource
    *           actual datasource to use
    * @see javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource()
    */
   void setDataSource(DataSource datasource);

   /**
    * Set the Hibernate RegionFactory to use for the SessionFactory. Allows for using a
    * Spring-managed RegionFactory instance.
    * <p/>
    * <p>
    * Note: If this is set, the Hibernate settings should not define a cache provider to avoid
    * meaningless double configuration.
    * 
    * @param cacheRegionFactory
    *           cache provider
    * @see org.hibernate.cache.RegionFactory
    */
   void setCacheRegionFactory(Object cacheRegionFactory);
}
